package com.milhouz.pokertimer.model;

import java.util.HashMap;
import java.util.Map;

import com.milhouz.pokertimer.constant.PriceRateConstant;

public class MainDataTimer extends AbstractPkr {

	private TimerData currentTimerData;
	
	// Game data
	private int nbPlayers;
	private int startingStack;
	private int totalStack;
	
	// Prices data
	private boolean hasPrice = false;
	private double playerFee;
	private int nbPrices;
	private double totalPrice;
	private int selectedPattern;
	private Map<Integer, Double> pricesPercentages;
	private Map<Integer, Double> priceByRank;

	// Blinds data
	private BlindList blinds;
	private int nbMinuteRound;
	private int nbRounds = NB_ROUNDS;
	private Double firstSmallBlind;
	private Double blindStep;

	private boolean isDataFromUserPref = false;
	
	/**
	 * Default Data Timer Initialization
	 */
	public MainDataTimer(String nbPlayers, String startingStack, String timeRound, String firstSmallBlind, String blindStep, String defaultNbPrices) {
		// Initialize main values
		this.currentTimerData = new TimerData(Long.valueOf(timeRound));
		this.nbPlayers = Integer.valueOf(nbPlayers);
		this.startingStack = Integer.valueOf(startingStack);
		this.nbMinuteRound = Integer.valueOf(timeRound);
		this.firstSmallBlind = Double.valueOf(firstSmallBlind);
		this.blindStep = Double.valueOf(blindStep);
		this.nbPrices = Integer.valueOf(defaultNbPrices);
		this.hasPrice = false;
		this.isDataFromUserPref = false;
		
		// update other values
		this.updateAll();
	}
	
	/**
	 * Data Timer Initialisation from Preferences
	 * @param data preference data
	 */
	public void updateFromPreferences(Map<String, ?> data) {
		// Initialize main values
		if (data.containsKey("nbPlayers") && data.get("nbPlayers") != null)
			this.nbPlayers = Integer.valueOf(String.valueOf(data.get("nbPlayers")));
		if (data.containsKey("startingStack") && data.get("startingStack") != null)
			this.startingStack = Integer.valueOf(String.valueOf(data.get("startingStack")));
		if (data.containsKey("timeRound") && data.get("timeRound") != null)
			this.nbMinuteRound = Integer.valueOf(String.valueOf(data.get("timeRound")));
		if (data.containsKey("firstSmallBlind") && data.get("firstSmallBlind") != null)
			this.firstSmallBlind = Double.valueOf(String.valueOf(data.get("firstSmallBlind")));
		if (data.containsKey("blindStep") && data.get("blindStep") != null)
			this.blindStep = Double.valueOf(String.valueOf(data.get("blindStep")));
		if (data.containsKey("nbPrizes") && data.get("nbPrizes") != null)
			this.nbPrices = Integer.valueOf(String.valueOf(data.get("nbPrizes")));
		if (data.containsKey("pricePatternList") && data.get("pricePatternList") != null)
			this.selectedPattern =Integer.valueOf(String.valueOf(data.get("pricePatternList")));
		
		this.isDataFromUserPref = true;
		this.currentTimerData = new TimerData(this.nbMinuteRound);
		
		// Initialize prices
		if (data.containsKey("hasPrizes") && data.get("hasPrizes") != null)
			this.hasPrice = Boolean.valueOf(String.valueOf(data.get("hasPrizes")));
		if (hasPrice) {
			if (data.containsKey("playerFee") && data.get("playerFee") != null)
				this.playerFee = Double.valueOf(String.valueOf(data.get("playerFee")));
			
			if (PriceRateConstant.PRICE_RATE.get(nbPrices) != null) {
				this.pricesPercentages = PriceRateConstant.PRICE_RATE.get(nbPrices).get(selectedPattern);
				this.priceByRank = new HashMap<Integer, Double>();
				for (Integer key : this.pricesPercentages.keySet()) {
					this.priceByRank.put(key, ((this.playerFee * this.nbPlayers) * this.pricesPercentages.get(key)) / 100);
				}
			}
		}

		// update other values
		this.updateAll();
	}
	
	/**
	 * Go to the next round
	 */
	public void nextRound() {
		if (getCurrentRound() <= nbRounds) {
			currentTimerData.nextRound();
			Blind newRoundBlinds = this.blinds.getBlindByRound(currentTimerData.getCurrentRound());
			if (newRoundBlinds != null) {
				currentTimerData.nextRoundTime(newRoundBlinds.getTime());
				currentTimerData.setCurrentSmallBlind(newRoundBlinds.getSmallBlind());
				currentTimerData.setCurrentBigBlind(newRoundBlinds.getBigBlind());
			}
		}
	}
	
	/**
	 * Go to the previous round
	 */
	public void previousRound() {
		if (getCurrentRound() > 0) {
			currentTimerData.previousRound();
			Blind newRoundBlinds = this.blinds.getBlindByRound(currentTimerData.getCurrentRound());
			if (newRoundBlinds != null) {
				currentTimerData.previousRoundTime(newRoundBlinds.getTime());
				currentTimerData.setCurrentSmallBlind(newRoundBlinds.getSmallBlind());
				currentTimerData.setCurrentBigBlind(newRoundBlinds.getBigBlind());
			}
		}
	}
	
	/**
	 * Return the current round number
	 * @return the round number
	 */
	public int getCurrentRound() {
		return currentTimerData.getCurrentRound();
	}
	
	/**
	 * Return the current round time in min
	 * @return time in min
	 */
	public long getCurrentRoundTime() {
		return currentTimerData.getCurrentTime();
	}
	
	/**
	 * Return the current small blind
	 * @return the current small blind
	 */
	public double getCurrentSmallBlind() {
		return this.blinds.getBlindByRound(getCurrentRound()).getSmallBlind();
	}
	
	/**
	 * Return the current big blind
	 * @return the current big blind
	 */
	public double getCurrentBigBlind() {
		return this.blinds.getBlindByRound(getCurrentRound()).getBigBlind();
	}

	// update all
	public void updateAll() {
		updateStack();
		updatePrices();
		updateBlinds();
	}
	
	// update stack
	private void updateStack() {
		totalStack = nbPlayers * startingStack;
	}

	// update prices
	private void updatePrices() {
		if (hasPrice && pricesPercentages != null && !pricesPercentages.isEmpty()) {
			totalPrice = playerFee * nbPlayers;
			priceByRank = new HashMap<Integer, Double>();
			for (Integer key : pricesPercentages.keySet()) {
				priceByRank.put(key, (pricesPercentages.get(key) * totalPrice) / 100);
			}
		}
	}

	// update blinds
	private void updateBlinds() {
		blinds = new BlindList();
		double tempSmallBlind = firstSmallBlind;
		for (int i = 1; i <= nbRounds; i++) {
			blinds.add(i, nbMinuteRound, tempSmallBlind);
			tempSmallBlind += this.blindStep;
		}
	}

	@Override
	public String toString() {
		StringBuffer sb = new StringBuffer();
		sb.append(" . Nb players         : ").append(nbPlayers).append("\n")//
		.append(" . Starting stack     : ").append(startingStack).append("\n")//
		.append(" . Total stack        : ").append(totalStack).append("\n")//
		.append(" . firstSmallBlind    : ").append(firstSmallBlind).append("\n")//
		.append(" . blindStep          : ").append(blindStep).append("\n")//
		.append(" . Nb rounds          : ").append(nbRounds).append("\n")//
		.append(" . nbMinuteRound      : ").append(nbMinuteRound).append("\n")//
		.append(" ... PRICES - ").append(hasPrice).append("\n")//
		.append(" . Nb prices          : ").append(nbPrices).append("\n")//
		.append(" . Price Fee          : ").append(playerFee).append("\n")//
		.append(" . Price Total        : ").append(totalPrice).append("\n")//
		.append(" . Prices percentages : ").append(pricesPercentages).append("\n")//
		.append(" . Prices by rank     : ").append(priceByRank).append("\n")//
		.append(" ... BLINDS\n").append(blinds);//
		return sb.toString();
	}

	public int getNbPlayers() {
		return nbPlayers;
	}

	public int getStartingStack() {
		return startingStack;
	}

	public int getTotalStack() {
		return totalStack;
	}

	public boolean isHasPrice() {
		return hasPrice;
	}

	public double getPlayerFee() {
		return playerFee;
	}

	public double getTotalPrice() {
		return totalPrice;
	}

	public Map<Integer, Double> getPricesPercentages() {
		return pricesPercentages;
	}

	public Map<Integer, Double> getPriceByRank() {
		return priceByRank;
	}

	public BlindList getBlinds() {
		return blinds;
	}

	public int getNbMinuteRound() {
		return nbMinuteRound;
	}

	public int getNbRounds() {
		return nbRounds;
	}

	public Double getFirstSmallBlind() {
		return firstSmallBlind;
	}

	public Double getBlindStep() {
		return blindStep;
	}

	public TimerData getTimerData() {
		return currentTimerData;
	}

	public void setNbRounds(int nbRounds) {
		this.nbRounds = nbRounds;
	}

	public boolean isDataFromUserPref() {
		return isDataFromUserPref;
	}
	
	public String getPricePercentageToString() {
		updatePrices();
		StringBuffer result = new StringBuffer("");
		if (hasPrice) {
			for (Integer key : priceByRank.keySet()) {
				if (pricesPercentages.containsKey(key) && priceByRank.containsKey(key)) {
					result.append(" ")
								.append(key)
								.append(". ")
								.append(String.format("%.1f", priceByRank.get(key)))
								.append(" $ (")
								.append(String.format("%d", pricesPercentages.get(key).intValue()))
								.append("%) \n")
								;
				}
			}
			result.append(String.format("  Total : %.0f $", totalPrice));
		}
		return result.toString();
	}

	
}
